package cn.tedu.charging.device.startup;

import cn.tedu.charging.device.dao.repository.StationRepository;
import cn.tedu.charging.device.pojo.po.StationPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 缓存预热 在项目启动的时候,从数据库查询场站信息到Redis
 * 场站的基本信息
 * 场站的位置信息
 */
@Slf4j
@Component
public class StationDataInit implements ApplicationRunner {

    @Autowired
    private StationRepository stationRepository;

    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;

    @PostConstruct
    public void init(){
        log.debug("@PostConstruct StationDataInit...");
    }



    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("ApplicationRunner#run StationDataInit...");
        log.debug("缓存预热,在项目启动时,从数据库查询场站位置信息(经纬度),基本信息(场站的信息),放到Redis");
        List<StationPO> stationPOs = stationRepository.getAllStation();
        log.debug("从数据库查询场站信息:{}",stationPOs);
        //为批量保存点信息做准备,key 场站id value point
        Map<Serializable,Point> pointMap = new HashMap<>();


        BoundGeoOperations<String, Serializable> stations =
                redisTemplate.boundGeoOps("stations");

        //GeoOperations<String, Serializable> geoOperations =
        //        redisTemplate.opsForGeo();


        if (!CollectionUtils.isEmpty(stationPOs)) {
            //循环场站列表
            for (StationPO stationPO : stationPOs) {
                Point point = saveGEO(stationPO);
                saveStringInfo(stationPO);
                saveHashInfo(stationPO);
                pointMap.put(String.valueOf(stationPO.getId()),point);
            }
            //geoOperations.add("stations",pointMap);
            log.debug("保存所有充电站位置信息到RedisGEO:{}",pointMap);
            stations.add(pointMap);
        }
    }

    @Autowired
    private RedisTemplate<String, StationPO> redisTemplateForStationPoStr;

    @Autowired
    private RedisTemplate<String, Map<String,Object>> redisTemplateForStationPoHash;


    /**
     * Map<String,String> redis的基本类型 String
     * 通过Redis String类型保存查找基本信息
     * key 场站id value 场站信息的Json
     * Map<String,String> redis的基本类型 聊的是 Map里的value
     * @param stationPO
     */
    private void saveStringInfo(StationPO stationPO) {
        ValueOperations<String, StationPO> str = redisTemplateForStationPoStr.opsForValue();
        String key = "station_info_string_" + stationPO.getId();
        str.set(key,stationPO);
    }

    /**
     * Map<String,Map<String,Object>> redis的基本类型 Hash

     * 通过Redis Hash类型保存查找基本信息
     * key 场站id value hash
     * Hash 是大map套小map
     * 聊的是 Map里的value 类型是Hash
     * Key:场站id
     * value: 小Map 小Map的key是 场站的字段(stationName) 小map里的值 : 字段对应的值(东安充电站)
     * @param stationPO
     */
    private void saveHashInfo(StationPO stationPO) {
        HashOperations<String, Object, Object> hash =
                redisTemplateForStationPoHash.opsForHash();
        String key = "station_info_hash_" + stationPO.getId();
        Map<String,Object> smallMap = new HashMap<>();
        smallMap.put("name",stationPO.getStationName());
        hash.putAll(key,smallMap);
    }

    /**
     * 保存位置相关信息
     * @param stationPO
     */
    private Point saveGEO(StationPO stationPO){
        //获取经纬
        BigDecimal stationLng = stationPO.getStationLng();
        //获取维度
        BigDecimal stationLat = stationPO.getStationLat();
        //awt swing java 做 UI
        //通过经纬度构建Redis的GEO中的 Point 点
        Point point = new Point(
                Double.parseDouble(stationLng.toEngineeringString()),
                Double.parseDouble(stationLat.toEngineeringString()));
        //放到map,为批量保存到Redis 准备
        log.debug("通过RedisGEO 保存场站位置信息key:{},value:{}",stationPO.getId(),point);
        return point;
    }
}
